#pragma once
#include <iostream>
#include <string>
#include <functional>

#include <cassert>
#include "mydll/Sock.hpp"
#include "Epoller.hpp"


namespace Epoll
{
    using namespace TCP;
    class Server
    {
        using func_t = std::function<std::string(const std::string&)>;
        const static int gnum = 64;
    public:
        Server(func_t func,int port=8088)
            :_port(port)
            ,_ss(_port)
            ,_func(func)
        {}

        void Init()
        {
            _ss.Socket();
            _ss.Bind();
            _ss.Listen();

            //创建Epoll文件file
            _ep.Create();
        }

        void Start()
        {
            //1.将服务器sockfd放入监听
            if(!_ep.AddEvent(_ss.GetSockFd(),EPOLLIN)) { assert(false); }

            int timeout = -1; //阻塞式监视
            while(true)
            {
                int n = _ep.Wait(_revs,gnum,timeout);
                switch(n)
                {
                    case 0:
                    {
                        logMessage(Debug, "timeout...");
                        break;
                    }
                    case -1:
                    {
                         logMessage(Warning, "epoll_wait failed");
                         break;
                    }
                    default:
                    {
                        logMessage(Debug, "有%d个事件就绪了", n);
                        HandlerEvents(n); //n表示有多少个文件描述符就绪
                        break;
                    }
                }
            }
        }

        ~Server() 
        {
            _ss.Close_Sockfd();
            _ep.Close();
        }

    protected:

        void HandlerEvents(int n)
        {
            for(int i = 0;i<n;++i)
            {
                int fd = _revs[i].data.fd;
                uint32_t event = _revs[i].events;

                if(event & EPOLLIN) //读事件
                {
                    if(fd == _ss.GetSockFd()) //fd为服务器id
                    {
                        std::string client_ip;
                        uint16_t client_port;
                        int client_sock = _ss.Accept(&client_ip,&client_port);
                        if(client_sock < 0) continue;

                        //服务器默认连接的文件描述符一开始是读取(向服务器写内容)
                        if(!_ep.AddEvent(client_sock,EPOLLIN))
                        {
                            close(client_sock); //加入失败则关闭连接
                            logMessage(Warning,"client AddEvent error!");
                            continue;
                        }
                    }
                    else //其他普通读取描述符 读取信息
                    {
                        char buf[1024] = {0}; //这里仍然无法保证一个应用层报文能读完整
                        int rsize = recv(fd,buf,sizeof(buf)-1,0);
                        if(rsize > 0)
                        {
                            buf[rsize] = '\0';
                            std::cout<<"client: "<<buf<<std::endl;
                            std::string request(buf);
                            std::string response = _func(request);
                            
                            send(fd,response.c_str(),response.size(),0);
                        }
                        else 
                        {
                            if(rsize == 0) //对端关闭了连接
                                logMessage(Info,"client quit! fd:%d",fd);
                            else //异常情况
                                logMessage(Error,"recv error! client quit! fd:%d",fd);

                            //先从epoll中删除fd信息再关闭fd 否则不安全
                            _ep.DelEvent(fd);
                            close(fd);
                        }
                    }
                }
                else if(event & EPOLLOUT) // 写事件
                {}
                else //其他事件
                {}
            }
        }

    private:
        uint16_t _port;
        SockServer _ss;
        Epoller _ep;
        struct epoll_event _revs[gnum]; //事件管理数组 接受每一个fd所就绪的事件
        func_t _func; //任务处理函数
    };
}